#include "base/atomic.h"
#include "net/tcp_listener.h"
#include "callback/callback.h"
#include "thread/thread_manage.h"

namespace weilin {

	TcpListener::TcpListener(const string& ip, const uint16_t& port, const call_back_shared_ptr& call_back_sp)
		:m_endpoint(boost::asio::ip::address::from_string(ip.c_str()), port),
		m_io_service(ThreadManage::Instance()->GetAcceptIoService()),
		m_call_back_sp(call_back_sp),
		m_accpetor(m_io_service),
		m_status(STATUS_IDLE)
	{

	}

	TcpListener::~TcpListener()
	{
		Stop();
	}

	bool TcpListener::Init()
	{
		if (AtomicCompareExchange(&m_status, STATUS_IDLE, STATUS_INIT) == false)
		{
			std::cout << FILE_LINE_FUNCTION << " to many thread error" << std::endl;
			AtomicSet<Status>(&m_status, STATUS_FAIL);
			return false;
		}

		boost::system::error_code ec;
		ec.clear();
		m_accpetor.open(m_endpoint.protocol(), ec);
		if (ec)
		{
			std::cout << FILE_LINE_FUNCTION << " open error" << std::endl;
			AtomicSet<Status>(&m_status, STATUS_FAIL);
			return false;
		}

		boost::asio::socket_base::reuse_address reuse_option(true);
		m_accpetor.set_option(reuse_option);

		m_accpetor.bind(m_endpoint, ec);
		if (ec)
		{
			std::cout << FILE_LINE_FUNCTION << "bind " << m_endpoint.address() << ":" << m_endpoint.port() << " error" << std::endl;
			AtomicSet<Status>(&m_status, STATUS_FAIL);
			return false;
		}

		m_accpetor.listen(boost::asio::socket_base::max_connections, ec);
		if (ec)
		{
			std::cout << FILE_LINE_FUNCTION << "listen  " << m_endpoint.address() << ":" << m_endpoint.port() << " error" << std::endl;
			AtomicSet<Status>(&m_status, STATUS_FAIL);
			return false;
		}
		return true;
	}


	bool TcpListener::Start()
	{
		if (AtomicCompareExchange(&m_status, STATUS_INIT, STATUS_START) == false)
		{
			std::cout << FILE_LINE_FUNCTION << " to many thread error" << std::endl;
			AtomicSet<Status>(&m_status, STATUS_FAIL);
			return false;
		}
		m_io_service.post(boost::bind(&TcpListener::startAccept, shared_from_this()));
		return true;
	}

	bool TcpListener::Stop()
	{

		if (AtomicCompareExchange(&m_status, STATUS_START, STATUS_STOP) == false)
		{
			std::cout << FILE_LINE_FUNCTION << " to many thread error" << std::endl;
			AtomicSet<Status>(&m_status, STATUS_FAIL);
			return false;
		}
		boost::system::error_code ec;
		m_accpetor.close(ec);
		if (ec)
		{
			std::cout << FILE_LINE_FUNCTION << " m_accpet close error" << std::endl;
			return false;
		}
		return true;
	}

	void TcpListener::startAccept()
	{
		if (AtomicGet<Status>(&m_status) != STATUS_START)
		{
			std::cout << FILE_LINE_FUNCTION << " status is error" << std::endl;
			return;
		}
		socket_shared_ptr temp_socket_sp(new (std::nothrow)boost::asio::ip::tcp::socket(ThreadManage::Instance()->GetSocketIoService()));
		m_accpetor.async_accept(*temp_socket_sp, boost::bind(&TcpListener::acceptedHandleCb, shared_from_this(), temp_socket_sp, _1));
	}

	void TcpListener::acceptedHandleCb(const socket_shared_ptr& socket_sp, const boost::system::error_code& ec)
	{
		if (ec.value() != 0)
		{
			std::cout << FILE_LINE_FUNCTION << " accept error " << std::endl;
		}
		else
		{
			m_io_service.post(boost::bind(&CallBack::AcceptedHandle, m_call_back_sp, socket_sp));
		}
		//continue
		boost::asio::ip::tcp::no_delay no_delay_option(true);
		socket_sp->set_option(no_delay_option);
		uint32_t buff_size = 1024 * 1024 * 2;
		boost::asio::socket_base::send_buffer_size send_option(buff_size);
		socket_sp->set_option(send_option);
		boost::asio::socket_base::receive_buffer_size recv_option(buff_size);
		socket_sp->set_option(recv_option);
		boost::asio::socket_base::keep_alive alive_option(true);
		socket_sp->set_option(alive_option);

		//continue
		startAccept();
	}
}

